package org.dromara.system.service.impl;

import cn.hutool.json.JSONObject;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
import com.wechat.pay.java.service.payments.model.Transaction;
import lombok.SneakyThrows;
import org.apache.commons.lang3.RandomStringUtils;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.domain.ZtUserCoupon;
import org.dromara.system.domain.ZtUserVip;
import org.dromara.system.domain.ZtVip;
import org.dromara.system.mapper.ZtUserCouponMapper;
import org.dromara.system.mapper.ZtUserVipMapper;
import org.dromara.system.mapper.ZtVipMapper;
import org.dromara.system.utils.QuickStart;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.dromara.system.domain.bo.ZtUserVipOrderBo;
import org.dromara.system.domain.vo.ZtUserVipOrderVo;
import org.dromara.system.domain.ZtUserVipOrder;
import org.dromara.system.mapper.ZtUserVipOrderMapper;
import org.dromara.system.service.IZtUserVipOrderService;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 用户VIP订单Service业务层处理
 *
 * @author Lion Li
 * @date 2024-06-27
 */
@RequiredArgsConstructor
@Service
public class ZtUserVipOrderServiceImpl implements IZtUserVipOrderService {

    private final ZtUserVipOrderMapper baseMapper;
    private final ZtVipMapper ztVipMapper;
    private final ZtUserVipMapper ztUserVipMapper;
    private final ZtUserCouponMapper ztUserCouponMapper;

    /**
     * 查询用户VIP订单
     */
    @Override
    public ZtUserVipOrderVo queryById(Long id){
        return baseMapper.selectVoById(id);
    }

    /**
     * 查询用户VIP订单列表
     */
    @Override
    public TableDataInfo<ZtUserVipOrderVo> queryPageList(ZtUserVipOrderBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<ZtUserVipOrder> lqw = buildQueryWrapper(bo);
        Page<ZtUserVipOrderVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询用户VIP订单列表
     */
    @Override
    public List<ZtUserVipOrderVo> queryList(ZtUserVipOrderBo bo) {
        LambdaQueryWrapper<ZtUserVipOrder> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<ZtUserVipOrder> buildQueryWrapper(ZtUserVipOrderBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<ZtUserVipOrder> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getVipId() != null, ZtUserVipOrder::getVipId, bo.getVipId());
        lqw.eq(bo.getUserId() != null, ZtUserVipOrder::getUserId, bo.getUserId());
        lqw.eq(bo.getAmountTotal() != null, ZtUserVipOrder::getAmountTotal, bo.getAmountTotal());
        lqw.eq(StringUtils.isNotBlank(bo.getAppid()), ZtUserVipOrder::getAppid, bo.getAppid());
        lqw.eq(StringUtils.isNotBlank(bo.getMchid()), ZtUserVipOrder::getMchid, bo.getMchid());
        lqw.eq(StringUtils.isNotBlank(bo.getDescription()), ZtUserVipOrder::getDescription, bo.getDescription());
        lqw.eq(StringUtils.isNotBlank(bo.getOutTradeNo()), ZtUserVipOrder::getOutTradeNo, bo.getOutTradeNo());
        lqw.eq(StringUtils.isNotBlank(bo.getTimeExpire()), ZtUserVipOrder::getTimeExpire, bo.getTimeExpire());
        lqw.eq(StringUtils.isNotBlank(bo.getAttach()), ZtUserVipOrder::getAttach, bo.getAttach());
        lqw.eq(StringUtils.isNotBlank(bo.getGoodsTag()), ZtUserVipOrder::getGoodsTag, bo.getGoodsTag());
        lqw.eq(bo.getSupportFapiao() != null, ZtUserVipOrder::getSupportFapiao, bo.getSupportFapiao());
        lqw.eq(StringUtils.isNotBlank(bo.getCurrency()), ZtUserVipOrder::getCurrency, bo.getCurrency());
        lqw.eq(StringUtils.isNotBlank(bo.getOpenid()), ZtUserVipOrder::getOpenid, bo.getOpenid());
        lqw.eq(StringUtils.isNotBlank(bo.getPrepayId()), ZtUserVipOrder::getPrepayId, bo.getPrepayId());
        lqw.eq(StringUtils.isNotBlank(bo.getTransactionId()), ZtUserVipOrder::getTransactionId, bo.getTransactionId());
        lqw.eq(StringUtils.isNotBlank(bo.getTradeType()), ZtUserVipOrder::getTradeType, bo.getTradeType());
        lqw.eq(StringUtils.isNotBlank(bo.getTradeState()), ZtUserVipOrder::getTradeState, bo.getTradeState());
        lqw.eq(StringUtils.isNotBlank(bo.getTradeStateDesc()), ZtUserVipOrder::getTradeStateDesc, bo.getTradeStateDesc());
        lqw.eq(StringUtils.isNotBlank(bo.getBankType()), ZtUserVipOrder::getBankType, bo.getBankType());
        lqw.eq(StringUtils.isNotBlank(bo.getSuccessTime()), ZtUserVipOrder::getSuccessTime, bo.getSuccessTime());
        lqw.eq(StringUtils.isNotBlank(bo.getPayerOpenid()), ZtUserVipOrder::getPayerOpenid, bo.getPayerOpenid());
        lqw.eq(bo.getPayerTotal() != null, ZtUserVipOrder::getPayerTotal, bo.getPayerTotal());
        lqw.eq(StringUtils.isNotBlank(bo.getPayerCurrency()), ZtUserVipOrder::getPayerCurrency, bo.getPayerCurrency());
        return lqw;
    }

    /**
     * 新增用户VIP订单
     */
    @Override
    public Boolean insertByBo(ZtUserVipOrderBo bo) {
        ZtUserVipOrder add = MapstructUtils.convert(bo, ZtUserVipOrder.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改用户VIP订单
     */
    @Override
    public Boolean updateByBo(ZtUserVipOrderBo bo) {
        ZtUserVipOrder update = MapstructUtils.convert(bo, ZtUserVipOrder.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(ZtUserVipOrder entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除用户VIP订单
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    /**
     * 用户下单
     *
     * @param bo
     */
    @SneakyThrows
    @Transactional(rollbackFor = Exception.class)
    @Override
    public R<PrepayWithRequestPaymentResponse> userPlacesAnOrder(ZtUserVipOrderBo bo) {
        Date date = new Date();
        bo.setUserId(LoginHelper.getLoginUser().getUserId());
        bo.setOpenid(LoginHelper.getLoginUser().getUsername());
        ZtUserVip ztUserVip = ztUserVipMapper.selectOne(new LambdaQueryWrapper<ZtUserVip>().eq(ZtUserVip::getUserId,bo.getUserId()));

        ZtVip ztVip = ztVipMapper.selectById(bo.getVipId());//下单的VIP
        if(ztVip == null || !"Y".equals(ztVip.getStatus())){
            return R.fail("下单失败，不存在该VIP套餐");
        }
        if("Y".equals(ztVip.getFirstOrder()) && ztUserVip != null){//判断是否是首单VIP
            return R.fail("下单失败，不存在该首单VIP套餐");
        }
        BigDecimal multipliedValue = ztVip.getSpecialPrice().multiply(new BigDecimal(100));
        bo.setAmountTotal(multipliedValue.longValueExact());
        if(bo.getUserCouponId() != null){
            ZtUserCoupon ztUserCoupon = ztUserCouponMapper.selectById(bo.getUserCouponId());//使用的优惠卷
            if(ztUserCoupon.getBeginDate().before(date) && ztUserCoupon.getEndDate().after(date)
                && "0".equals(ztUserCoupon.getWhetherToUse())
                && ztUserCoupon.getMinAmount().compareTo(multipliedValue) <= 0){//判断优惠卷是否有效
                if("01".equals(ztUserCoupon.getType())){//满减卷
                    BigDecimal multipliedValue_1 = ztUserCoupon.getAmountOfMoney().multiply(new BigDecimal(100));
                    bo.setAmountTotal(multipliedValue.longValueExact()-multipliedValue_1.longValueExact());
                }else if("02".equals(ztUserCoupon.getType())){//折扣卷
                    bo.setAmountTotal(multipliedValue.multiply(ztUserCoupon.getAmountOfMoney().divide(new BigDecimal(10))).longValueExact());
                }else{
                    return R.fail("下单失败，无效的优惠卷");
                }
            }else{
                return R.fail("下单失败，无效的优惠卷");
            }
        }
        bo.setAppid(LoginHelper.getLoginUser().getClientKey());
        bo.setDescription(ztVip.getTermOfValidity()+"天"+ztVip.getName());
        bo.setOutTradeNo(getOrderNum());
        PrepayWithRequestPaymentResponse response = QuickStart.userPlacesAnOrder(bo);//微信下单
        if(StringUtils.isNotBlank(bo.getPrepayId()) && this.insertByBo(bo)){
            return R.ok("下单成功",response);
        }
        return R.fail("下单失败");
    }

    /**
     * 微信支付通知
     * @param headers
     * @param body
     * @return
     */
    @SneakyThrows
    @Transactional(rollbackFor = Exception.class)
    @Override
    public JSONObject wxNotify(HttpHeaders headers, String body) {
        LocalDateTime now = LocalDateTime.now();
        JSONObject json = new JSONObject();
        Transaction transaction = QuickStart.decrypt(headers,body);
        if(transaction != null && StringUtils.isNotEmpty(transaction.getOutTradeNo())){
            ZtUserVipOrder ztUserVipOrder = baseMapper.selectOne(new LambdaQueryWrapper<ZtUserVipOrder>().eq(ZtUserVipOrder::getOutTradeNo,transaction.getOutTradeNo()));
            if(ztUserVipOrder != null){
                ztUserVipOrder.setTransactionId(transaction.getTransactionId());
                ztUserVipOrder.setTradeType(transaction.getTradeType().toString());
                ztUserVipOrder.setTradeState(transaction.getTradeState().toString());
                ztUserVipOrder.setTradeStateDesc(transaction.getTradeStateDesc());
                ztUserVipOrder.setBankType(transaction.getBankType());
                ztUserVipOrder.setSuccessTime(transaction.getSuccessTime());
                ztUserVipOrder.setPayerOpenid(transaction.getPayer().getOpenid());
                ztUserVipOrder.setPayerTotal(Long.parseLong(transaction.getAmount().getPayerTotal().toString()));
                ztUserVipOrder.setPayerCurrency(transaction.getAmount().getPayerCurrency());
                baseMapper.updateById(ztUserVipOrder);
                ZtUserVip ztUserVip = ztUserVipMapper.selectOne(new LambdaQueryWrapper<ZtUserVip>().eq(ZtUserVip::getUserId,ztUserVipOrder.getUserId()));
                ZtVip ztVip = ztVipMapper.selectById(ztUserVipOrder.getVipId());
                int count = 0;
                if(ztUserVip == null){
                    LocalDateTime futureDate = now.plusDays(ztVip.getTermOfValidity());
                    ztUserVip = new ZtUserVip();
                    ztUserVip.setUserId(ztUserVipOrder.getUserId());
                    ztUserVip.setEffectiveEndDate(Date.from(futureDate.atZone(ZoneId.systemDefault()).toInstant()));
                    count = ztUserVipMapper.insert(ztUserVip);
                }else if(ztUserVip.getEffectiveEndDate().after(new Date())){
                    LocalDateTime localDateTime = ztUserVip.getEffectiveEndDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
                    LocalDateTime futureDate = localDateTime.plusDays(ztVip.getTermOfValidity());
                    ztUserVip.setEffectiveEndDate(Date.from(futureDate.atZone(ZoneId.systemDefault()).toInstant()));
                    count = ztUserVipMapper.updateById(ztUserVip);
                }else{
                    LocalDateTime futureDate = now.plusDays(ztVip.getTermOfValidity());
                    ztUserVip.setEffectiveEndDate(Date.from(futureDate.atZone(ZoneId.systemDefault()).toInstant()));
                    count = ztUserVipMapper.updateById(ztUserVip);
                }
                if(count > 0){
                    if(ztUserVipOrder.getUserCouponId() != null){
                        ZtUserCoupon ztUserCoupon = ztUserCouponMapper.selectById(ztUserVipOrder.getUserCouponId());
                        ztUserCoupon.setWhetherToUse("1");
                        if(ztUserCouponMapper.updateById(ztUserCoupon) == 0){
                            throw new Exception();
                        }
                    }
                    json.putOpt("code","SUCCESS");
                    json.putOpt("message","成功");
                    ResponseEntity.status(HttpStatus.OK);
                    return json;
                }
            }
        }
        json.putOpt("code","FAIL");
        json.putOpt("message","失败");
        ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR);
        return json;
    }

    /**
     * 生成订单号（20位）：时间（精确到毫秒）+3位随机数
     * @return
     */
    public static synchronized  String getOrderNum() {
        //时间（精确到毫秒）
        DateTimeFormatter ofPattern = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
        String localDate = LocalDateTime.now().format(ofPattern);
        //3位随机数
        String randomNumeric = RandomStringUtils.randomNumeric(3);
        String orderNum = localDate + randomNumeric;
        return orderNum;
    }
}
